﻿using System;

//
// Created by Arosy on 2021/11/21.
//
//
// Created by Arosy on 2021/11/21.
//



public class ClassFileParser:FileC
{
	//#pragma comment(lib, "wsock32.lib")
	public static InstanceKlass Parser(ClassRead classRead)
	{
		InstanceKlass klass = new InstanceKlass();
		checkAndPutMagic(classRead, klass); //校验是否是class文件
		checkAndPutVersion(classRead, klass); //校验版本号
		parserConstantPoolCount(classRead, klass); //解析常量池数量
		parserConstantPool(classRead, klass); //解析常量池
		parserAccessFlags(classRead, klass); //解析访问权限
		parserThisClass(classRead, klass); //类名
		parserSuperClass(classRead, klass); //父类名
		parserInterfacesCount(classRead, klass); //解析出接口数量
		parserInterfaces(classRead, klass); //根据数量解析接口
		parserFieldsCount(classRead, klass); //解析字段数量
		parserFieldsInfo(classRead, klass); //根据数量解析字段
		parserMethodCount(classRead, klass); //解析方法数量
		parserMethodInfo(classRead, klass); //解析方法
		parserAttributeCount(classRead, klass); //解析属性数量
		parserAttribute(classRead, klass); //解析属性
		return klass;
	}
	public static void checkAndPutMagic(ClassRead classRead, InstanceKlass klass)
	{
		klass.setMagic(classRead.readByFourByte()); //读取4个字节并set进InstanceKlass的magic属性中
        if (klass.getMagic() == DefineConstants.MAGIC)
        { //校验magic属性是否等于0xCAFEBABE
            Console.Write("class文件校验正确\n");
            return;
        }
        Console.Write("class文件校验错误，{0:X}\n", klass.getMagic());
	}
	public static void checkAndPutVersion(ClassRead classRead, InstanceKlass klass)
	{
		klass.setMinorVersion(classRead.readByTwoByte()); //读取两个字节作为次版本号set进InstanceKlass属性
		klass.setMajorVersion(classRead.readByTwoByte()); //读取两个字节作为主版本号set进InstanceKlass属性
		Console.Write("次版本号：{0:D}\n", klass.getMinorVersion());
		Console.Write("主版本号：{0:D}\n", klass.getMajorVersion());
		switch (klass.getMajorVersion())
		{ //校验版本号是否在允许范围内
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not allow fall-through from a non-empty 'case':
			case 46:
			case 47:
			case 48:
			case 49:
			case 50:
			case 51:
			case 52:
			{
				if (klass.getMinorVersion() == 0)
				{
					Console.Write("版本校验正确\n");
					return;
				}
			}
			break;
		}
		Console.Write("版本校验错误\n");
	}
	public static void parserConstantPoolCount(ClassRead classRead, InstanceKlass klass)
	{
		klass.setConstantPoolCount(classRead.readByTwoByte()); //读取两个字节获取到常量池的数量，并set进InstanceKlass属性
	}
	public static void parserConstantPool(ClassRead classRead, InstanceKlass klass)
	{
		klass.setConstantPool(new ConstantPool()); //为常量池初始化内存空间
		ConstantPool constantPool = klass.getConstantPool();
		//constantPool.tag = new string(new char[klass.getConstantPoolCount() - 1]); //根据常量池数量初始化常量池数据区的内存空间
		constantPool.tag = new byte[klass.getConstantPoolCount() - 1]; //根据常量池数量初始化常量池数据区的内存空间

        for (int i = 1; i < klass.getConstantPoolCount(); i++)
		{
			byte tag = classRead.readByOneByte(); //读取一个字节获取到类型的映射值
			constantPool.tag[i] = tag; //存储类型
			switch (tag)
			{ //根据不同的类型，有不同的处理方式，主要是读取的字节数不同
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not allow fall-through from a non-empty 'case':
				case DefineConstants.CONSTANT_Utf8:
				{
					ushort len = classRead.readByTwoByte(); //读两个字节作为utf-8的字节长度
					//string target = new string(new char[len]); //申请len+1长度的字节内存，c语言最后一位需要用'\0'填充
					byte[] target = new byte[len]; //申请len+1长度的字节内存，c语言最后一位需要用'\0'填充
                        classRead.readByFreeByte((short)len,  target); //读取len个字节
					(constantPool.data[i]) = target; //存储在常量池
					Console.Write("第{0:D}个，类型utf-8，值{1}\n", i, constantPool.data[i]);
					break;
				}
				case DefineConstants.CONSTANT_Integer:
				{
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte *temp = new sbyte();
					uint temp = new uint();
					temp = classRead.readByFourByte(); //读取四个字节
					constantPool.data[i] = temp; //存储在常量池
					Console.Write("第{0:D}个，类型Integer，值{1:D}\n", i, constantPool.data[i]);
					break;
				}
				case DefineConstants.CONSTANT_Float:
				{
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte *temp = new sbyte();
					uint temp = new uint();
					temp = classRead.readByFourByte(); //读取四个字节
					constantPool.data[i] = temp; //存储在常量池
					Console.Write("第{0:D}个，类型Float，值{1:D}\n", i, constantPool.data[i]);
					break;
				}
				case DefineConstants.CONSTANT_Long:
				{
					Console.Write("暂不处理\n");
					break;
				}
				case DefineConstants.CONSTANT_Double:
				{
					Console.Write("暂不处理\n");
					break;
				}
				case DefineConstants.CONSTANT_Class:
				{
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: sbyte *temp = new sbyte();
					ushort temp = new ushort ();
					temp = classRead.readByTwoByte(); //读取两个字节
					constantPool.data[i] = temp; //存储在常量池
					Console.Write("第{0:D}个，类型Class，值{1:D}\n", i, constantPool.data[i]);
					break;
				}
				case DefineConstants.CONSTANT_String:
				{
                        //string temp = new string(new char[2]);
                        string temp = classRead.readByTwoByte().ToString (); //读取两个字节
					//temp = StringFunctions.ChangeCharacter(temp, 2, '\0');
					temp = temp+'\0';
                        constantPool.data[i] = temp; //存储在常量池
					Console.Write("第{0:D}个，类型String，值{1:D}\n", i, constantPool.data[i]);
					break;
				}
				case DefineConstants.CONSTANT_Fieldref:
				case DefineConstants.CONSTANT_Methodref:
				case DefineConstants.CONSTANT_InterfaceMethodref:
				{
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: int *temp = new int();
					int temp = new int(); //申请四个字节的内存空间
					ushort classIndex = classRead.readByTwoByte(); //读取两个字节
					ushort nameAndTypeIndex = classRead.readByTwoByte(); //读取两个字节
					temp = htonl(classIndex << 16 | nameAndTypeIndex); //左16位存储classIndex 右16为存储nameAndTypeIndex
					(constantPool.data[i]) =  temp; //存储在常量池
					Console.Write("第{0:D}个，类型file、method、Interface Methodref，值{1:X}\n", i, htonl((int) constantPool.data[i]));
					break;
				}
				case DefineConstants.CONSTANT_NameAndType:
				{
//C++ TO C# CONVERTER CRACKED BY X-CRACKER 2017 TODO TASK: C# does not have an equivalent to pointers to value types:
//ORIGINAL LINE: int *temp = new int();
					int temp = new int();
					ushort nameIndex = classRead.readByTwoByte(); //读取两个字节
					ushort descriptorIndex = classRead.readByTwoByte(); //读取两个字节
					temp = htonl(nameIndex << 16 | descriptorIndex); //左16位存储classIndex 右16为存储nameAndTypeIndex
					(constantPool.data[i]) =  temp; //存储在常量池
					Console.Write("第{0:D}个，类型NameAndType，值{1:X}\n", i, htonl((int) constantPool.data[i]));
					break;
				}
				default:
					break;
			}

		}
	}
	public static void parserAccessFlags(ClassRead classRead, InstanceKlass klass)
	{
		klass.setAccessFlags((short)classRead.readByTwoByte()); //读取两个字节，set进InstanceKlass属性
		Console.Write("访问权限：{0:D}\n", klass.getAccessFlags());
	}
	public static void parserThisClass(ClassRead classRead, InstanceKlass klass)
	{
		klass.setThisClass((short)classRead.readByTwoByte()); //读取两个字节，set进InstanceKlass属性
		Console.Write("类名：{0:X}\n", klass.getThisClass());
	}
	public static void parserSuperClass(ClassRead classRead, InstanceKlass klass)
	{
		klass.setSuperClass((short)classRead.readByTwoByte()); //读取两个字节，set进InstanceKlass属性
		Console.Write("父类名：{0:X}\n", klass.getSuperClass());
	}
	public static void parserInterfacesCount(ClassRead classRead, InstanceKlass klass)
	{
		klass.setInterfacesCount((short)classRead.readByTwoByte()); //往后读取两个字节set进InstanceKlass中的接口数量属性
		Console.Write("接口数量：{0:D}\n", klass.getInterfacesCount());
	}
	public static void parserInterfaces(ClassRead classRead, InstanceKlass klass)
	{
		if (klass.getInterfacesCount() == 0)
		{
			return; //未实现接口就不解析了
		}
		klass.setInterfaces(Arrays.InitializeWithDefaultInstances<InterfacesInfo>(klass.getInterfacesCount()));
		InterfacesInfo[] interfaces = klass.getInterfaces();
		for (int i = 0; i < klass.getInterfacesCount(); i++)
		{
			ushort constantPoolIndex = classRead.readByTwoByte(); //往后读取两个字节作为常量池索引
			int index = (int)(klass.getConstantPool().data[constantPoolIndex]); //获取新的常量池索引
			string name = ((char)klass.getConstantPool().data[index]).ToString(); //第二次索引取得全限定名
			Console.Write("第{0:D}个接口，name:{1},索引位置：{2:D}", i + 1, name, constantPoolIndex);
			interfaces [ i] = new InterfacesInfo((short)constantPoolIndex, name); //将接口set进InstanceKlass属性中
		}
	}
	public static void parserFieldsCount(ClassRead classRead, InstanceKlass klass)
	{
		klass.setFieldsCount((short)classRead.readByTwoByte()); //往后读取两个字节set进InstanceKlass中的字段数量属性
		Console.Write("字段数量：{0:D}\n", klass.getFieldsCount());
	}
	public static void parserFieldsInfo(ClassRead classRead, InstanceKlass klass)
	{
		klass.setFieldsInfo(Arrays.InitializeWithDefaultInstances<FieldsInfo>(klass.getFieldsCount())); //按照字段数量初始化字段内存空间
		FieldsInfo[] fieldsInfo = klass.getFieldsInfo();
		for (int i = 0; i < klass.getFieldsCount(); i++)
		{ //循环字段数量count次，解析字段
			//FieldsInfo fields = (fieldsInfo + i);
			FieldsInfo fields = new FieldsInfo();
            fields.setAccessFlag((short)classRead.readByTwoByte()); //往后读取两个字节set进FieldsInfo的访问权限
			fields.setNameIndex((short)classRead.readByTwoByte()); //往后读取两个字节set进FieldsInfo的name
			fields.setDescriptorIndex((short)classRead.readByTwoByte()); //往后读取两个字节set进FieldsInfo的类型描述
			fields.setAttributesCount((short)classRead.readByTwoByte()); //往后读取两个字节set进FieldsInfo的附加属性数量
            fieldsInfo[i] = fields;

            Console.Write("field 解析：\n access:{0:X},\n nameIndex:{1:X}\n descriptorIndex:{2:X} \n attributesCount:{3:X}\n", fields.getAccessFlag(), fields.getNameIndex(), fields.getDescriptorIndex(), fields.getAttributesCount());
		}
	}
	public static void parserMethodCount(ClassRead classRead, InstanceKlass klass)
	{
		klass.setMethodCount((short)classRead.readByTwoByte());
		Console.Write("方法数量：{0:D}\n", klass.getMethodCount());
	}
	public static void parserMethodInfo(ClassRead classRead, InstanceKlass klass)
	{
		klass.setMethodInfo(Arrays.InitializeWithDefaultInstances<MethodInfo>(klass.getMethodCount())); //初始化InstanceKlass中的methodInfo的内存空间
		for (int i = 0; i < klass.getMethodCount(); i++)
		{
			MethodInfo method = new MethodInfo();
			method.setBelongKlass(klass); //将方法与所属InstanceKlass关联
			method.setAccessFlags((short)classRead.readByTwoByte()); //存储方法的访问权限
			method.setNameIndex(classRead.readByTwoByte()); //存储方法的访问权限
			method.setMethodName((string) klass.getConstantPool().data[method.getNameIndex()]); //存储方法的名字
			Console.Write("解析方法{0}\n", method.getMethodName());
			method.setDescriptorIndex(classRead.readByTwoByte()); //存储方法的描述（包含了参数、返回值）
			method.setAttributesCount(classRead.readByTwoByte()); //存储属性数量
			method.initCodeAttributeInfo();
			klass.getMethodInfo() [ i] = method;
			for (int j = 0; j < method.getAttributesCount(); j++)
			{
				CodeAttributeInfo codeAttributeInfo = new CodeAttributeInfo();
				codeAttributeInfo.setAttrNameIndex(classRead.readByTwoByte()); //存储属性名字的常量池索引
				codeAttributeInfo.setAttrLength((short)classRead.readByFourByte()); //存储属性长度
				codeAttributeInfo.setMaxStack(classRead.readByTwoByte()); //存储最大栈深度
				codeAttributeInfo.setMaxLocals(classRead.readByTwoByte()); //存储局部变量表数量
				codeAttributeInfo.setCodeLength((short)classRead.readByFourByte()); //存储指令数量
				BytecodeStream bytecodeStream = new BytecodeStream(method, codeAttributeInfo, codeAttributeInfo.getCodeLength(), 0, new byte[codeAttributeInfo.getCodeLength()]);
				classRead.readByFreeByte((short)codeAttributeInfo.getCodeLength(), bytecodeStream.getCodes()); //重点： 将方法的JVM指令存储在bytecodeStream
				codeAttributeInfo.setCode(bytecodeStream);
				Console.Write("\t第{0:D}个属性，access flag:{1:X} name index : {2:X}  stack:{3:X} container:{4:X}  code length:{5:X} \n", j, method.getAccessFlags(), codeAttributeInfo.getAttrNameIndex(), codeAttributeInfo.getMaxStack(), codeAttributeInfo.getMaxLocals(), codeAttributeInfo.getCodeLength());
				codeAttributeInfo.setExceptionTableLength(classRead.readByTwoByte()); //存储Exception表长度，此处暂时为0，因为我们没有任何异常需要处理
				codeAttributeInfo.setAttributesCount(classRead.readByTwoByte()); //存储属性长度
				method.setAttributeInfo(codeAttributeInfo, j);
				for (int k = 0; k < codeAttributeInfo.getAttributesCount(); k++)
				{ //循环解析属性
					int nameIndex = classRead.readByTwoByte();
					string attrName = ((char)klass.getConstantPool().data[nameIndex]).ToString();
					if ("LineNumberTable" == attrName)
					{ //解析LineNumberTable
						parserLineNumberTable(classRead, codeAttributeInfo, attrName, nameIndex, klass);
					}
					else if ("LocalVariableTable" == attrName)
					{ //解析LocalVariableTable
						parseLocalVariableTable(classRead, codeAttributeInfo, attrName, nameIndex, klass);
					}
				}
			}
		}
	}
	public static void parserAttributeCount(ClassRead classRead, InstanceKlass klass)
	{
		klass.setAttributeCount((short)classRead.readByTwoByte()); //读取两个字节将属性数量存储在InstanceKlass中
		Console.Write("解析属性，数量{0:D}\n", klass.getAttributeCount());
	}
	public static void parserAttribute(ClassRead classRead, InstanceKlass klass)
	{
		for (int i = 0; i < klass.getAttributeCount(); i++)
		{
			ushort nameIndex = classRead.readByTwoByte();
			string attrName = ((char)klass.getConstantPool().data[nameIndex]).ToString();
			if ("SourceFile" == attrName)
			{
				Console.Write("\tSourceFile\n");
				parseSourceFile(classRead, klass, nameIndex, i); //解析SourceFile属性
			}
			else
			{
				Console.Write("\t无法识别的属性:{0:X}\n", attrName);
			}
		}
	}
	public static void parseSourceFile(ClassRead classRead, InstanceKlass klass, ushort nameIndex, int index)
	{
		klass.setAttributeInfo(Arrays.InitializeWithDefaultInstances<AttributeInfo>(klass.getAttributeCount())); //初始化内存空间来存储属性
		//AttributeInfo attributeInfo = klass.getAttributeInfo();
		AttributeInfo attributeInfo = new AttributeInfo ();
        klass.getAttributeInfo()[index] = attributeInfo;
		attributeInfo.setAttributeNameIndex((short)nameIndex); //存储属性name的常量池索引
		attributeInfo.setAttributeLength((int)classRead.readByFourByte()); //存储属性长度length
		attributeInfo.initContainer();
		attributeInfo.setContainer(classRead.readByTwoByte()); //存储文件名的常量池索引
		Console.Write("\t\t第{0:D}个属性，{1}:nameIndex:{2:D},length:{3:D},data:{4:D},({5})\n", index, klass.getConstantPool().data[nameIndex], attributeInfo.getAttributeNameIndex(), attributeInfo.getAttributeLength(), attributeInfo.getContainer(), klass.getConstantPool().data[attributeInfo.getContainer()]);
	}
	public static void parserLineNumberTable(ClassRead classRead, CodeAttributeInfo codeAttributeInfo, string attrName, int nameIndex, InstanceKlass klass)
	{
		LineNumberTable lineNumberTable = new LineNumberTable();
		(codeAttributeInfo.attributes)[attrName] = lineNumberTable;
		lineNumberTable.setAttributeNameIndex((short)nameIndex);
		lineNumberTable.setAttributeLength((short)classRead.readByFourByte());
		lineNumberTable.setTableLen((short)classRead.readByTwoByte());
		//lineNumberTable.table = Arrays.InitializeWithDefaultInstances<Item>(lineNumberTable.getTableLen());
		lineNumberTable.table = new LineNumberTable.Item[lineNumberTable.getTableLen()];
        if (lineNumberTable.getTableLen() == 0)
		{
			Console.Write("table len =0\n");
			return;
		}
		for (int i = 0; i < lineNumberTable.getTableLen(); i++)
		{
			LineNumberTable.Item item = new LineNumberTable.Item();
			lineNumberTable.table[i] = item;
			Console.Write("\t\tlineNumberTable: name index:{0:D},attr len:{1:D}, table len:{2:D}\n", lineNumberTable.getAttributeNameIndex(), lineNumberTable.getAttributeLength(), lineNumberTable.getTableLen());
			item.setStartPc((short)classRead.readByTwoByte());
			item.setLineNumber((short)classRead.readByTwoByte());
			Console.Write("\t\t\t第{0:D}个属性，start pc : {1:D},line numnber:{2:D}\n", i, item.getStartPc(), item.getLineNumber());
		}

	}
	public static void parseLocalVariableTable(ClassRead classRead, CodeAttributeInfo codeAttributeInfo, string attrName, int nameIndex, InstanceKlass klass)
	{
		LocalVariableTable localVariableTable = new LocalVariableTable();
		(codeAttributeInfo.attributes)[attrName] = localVariableTable;
		localVariableTable.setAttributeNameIndex((short)nameIndex);
		localVariableTable.setAttributeLength((int)classRead.readByFourByte());
		localVariableTable.setTableLen((short)classRead.readByTwoByte());
		//localVariableTable.table = Arrays.InitializeWithDefaultInstances<Item>(localVariableTable.getTableLen());
		localVariableTable.table = new LocalVariableTable.Item[localVariableTable.getTableLen()];
        if (localVariableTable.getTableLen() == 0)
		{
			Console.Write("table len =0\n");
			return;
		}
		for (int i = 0; i < localVariableTable.getTableLen(); i++)
		{
			LocalVariableTable.Item item = new LocalVariableTable.Item();
			localVariableTable.table[i] = item;
			item.setStartPc((short)classRead.readByTwoByte());
			item.setLength((short)classRead.readByTwoByte());
			item.setNameIndex((short)classRead.readByTwoByte());
			item.setDescriptorIndex((short)classRead.readByTwoByte());
			item.setIndex((short)classRead.readByTwoByte());
			Console.Write("\t\tLocalVariableTable:第{0:D}个属性，start pc:{1:D},length:{2:D},name index:{3:D},descrip:{4:D},index:{5:D}\n", i, item.getStartPc(), item.getLength(), item.getNameIndex(), item.getDescriptorIndex(), item.getIndex());
		}

	}

}





